#'
#' Singular Value Decomposition
#'
#' Singular value decomposition of an H2O data frame using the power method.
#'
#'
#' @param training_frame An H2OFrame object containing the
#'        variables in the model.
#' @param x (Optional) A vector containing the data columns on which SVD operates.
#' @param nv The number of right singular vectors to be computed. This must be
#'        between 1 and min(ncol(training_frame), nrow(training_frame)) inclusive.
#' @param destination_key (Optional) The unique hex key assigned to the
#'        resulting model. Automatically generated if none is provided.
#' @param max_iterations The maximum number of iterations to run each power
#'        iteration loop. Must be between 1 and 1e6 inclusive.
#' @param transform A character string that indicates how the training data
#'        should be transformed before running PCA. Possible values are: "NONE"
#'        for no transformation; "DEMEAN" for subtracting the mean of each
#'        column; "DESCALE" for dividing by the standard deviation of each
#'        column; "STANDARDIZE" for demeaning and descaling; and "NORMALIZE"
#'        for demeaning and dividing each column by its range (max - min).
#' @param svd_method A character string that indicates how SVD should be calculated.
#'        Possible values are "GramSVD": distributed computation of the Gram matrix
#'        followed by a local SVD using the JAMA package, "Power": computation of
#'        the SVD using the power iteration method, "Randomized": approximate SVD
#'        by projecting onto a random subspace (see references).
#' @param seed (Optional) Random seed used to initialize the right singular vectors
#'        at the beginning of each power method iteration.
#' @param use_all_factor_levels (Optional) A logical value indicating whether all
#'        factor levels should be included in each categorical column expansion.
#'        If FALSE, the indicator column corresponding to the first factor level
#'        of every categorical variable will be dropped. Defaults to TRUE.
#' @param max_runtime_secs Maximum allowed runtime in seconds for model training. Use 0 to disable.
#' @return Returns an object of class \linkS4class{H2ODimReductionModel}.
#' @references N. Halko, P.G. Martinsson, J.A. Tropp. {Finding structure with randomness: Probabilistic algorithms for constructing approximate matrix decompositions}[http://arxiv.org/abs/0909.4061]. SIAM Rev., Survey and Review section, Vol. 53, num. 2, pp. 217-288, June 2011.
#' @examples
#' \donttest{
#' library(h2o)
#' h2o.init()
#' ausPath <- system.file("extdata", "australia.csv", package="h2o")
#' australia.hex <- h2o.uploadFile(path = ausPath)
#' h2o.svd(training_frame = australia.hex, nv = 8)
#' }
#' @export
h2o.svd <- function(training_frame, x, nv,
                    ## AUTOGENERATED PARAMETERS ##     # these defaults are not read by h2o
                    destination_key,                   # h2o generates its own default parameters
                    max_iterations = 1000,
                    transform = "NONE",
                    svd_method = c("GramSVD", "Power", "Randomized"),
                    seed,
                    use_all_factor_levels,
                    max_runtime_secs=0)
{
  # Required args: training_frame
  if( missing(training_frame) ) stop("argument \"training_frame\" is missing, with no default")
  # Training_frame may be a key or an H2OFrame object
  if (!is.H2OFrame(training_frame))
    tryCatch(training_frame <- h2o.getFrame(training_frame),
             error = function(err) {
               stop("argument \"training_frame\" must be a valid H2OFrame or key")
             })

  # Gather user input
  parms <- list()
  parms$training_frame <- training_frame
  if(!missing(x))
    parms$ignored_columns <- .verify_datacols(training_frame, x)$cols_ignore
  if(!missing(nv))
    parms$nv <- as.numeric(nv)    # TODO: Want default to min(n,p) where n = nrow, p = ncol of adapted training_frame
  if(!missing(max_iterations))
    parms$max_iterations <- max_iterations
  if(!missing(transform))
    parms$transform <- transform
  if(!missing(svd_method))
    parms$svd_method <- svd_method
  if(!missing(seed))
    parms$seed <- seed
  if(!missing(use_all_factor_levels))
    parms$use_all_factor_levels <- use_all_factor_levels
  if(!missing(max_runtime_secs)) parms$max_runtime_secs <- max_runtime_secs

  # Error check and build model
  .h2o.modelJob('svd', parms, h2oRestApiVersion=99)
}
